package com.lhf.aicloud.utils.idempotent;

import cn.hutool.crypto.SecureUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lhf.aicloud.entity.SecurityUserDetails;
import com.lhf.aicloud.utils.SecurityUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.concurrent.TimeUnit;

/**
 * @author: lhf
 * @date: Created in 2024/08/16
 * @description:
 */
@Component
public class IdempotentInterceptor implements HandlerInterceptor {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
        Idempotent idempotent;
        try {
            idempotent = ((HandlerMethod) handler).getMethod().getAnnotation(Idempotent.class);
        } catch (Exception e) {
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        // 如果当前方法加了幂等性注解
        if (idempotent != null) {
            // 获取当前请求的唯一标识
            String requestId = createRequestId(request);
            // 如果Redis中存在，则说明请求重复
            if (redisTemplate.opsForValue().get(requestId) != null) {
                response.getWriter().write("do idempotent!");
                return false;
            } else {
                // 将请求唯一标识存入Redis，设置过期时间
                redisTemplate.opsForValue().set(requestId, "true", idempotent.time(), TimeUnit.SECONDS);
                return true;
            }
        }
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    /**
     * 生成幂等性id: MD5(用户ID + 请求参数)
     */
    private String createRequestId(HttpServletRequest request) throws JsonProcessingException {
        // 获取当前用户id
        Long uid = 0L;
        SecurityUserDetails userDetails = SecurityUtils.getCurrentUser();
        if (userDetails != null) {
            uid = userDetails.getUid();
        }
        String requestParam = objectMapper.writeValueAsString(request.getParameterMap());
        return SecureUtil.md5(uid + requestParam);
    }
}
